package com.apobates.forum.toro.core;

import com.apobates.forum.toro.utils.CommonHelper;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.stream.Stream;

/**
 * 第七版
 * 子匹配表达式. 通过开始和结束分隔符来断定是否满足指定word的表达式
 * @deprecated 使用SpaceMatcher
 * @author xiaofanku@live.cn
 * @since 20220829
 */
public class KideMatcher {
    // 开始分隔符
    private final String start;
    // 可能的尾分隔符
    private final String[] tail;
    // 所属的word
    private final String word;
    private final static Logger logger = LoggerFactory.getLogger(KideMatcher.class);

    public KideMatcher(String word, String start, String[] tail) {
        this.word = word;
        this.start = start;
        this.tail = tail;
    }

    public String getStart() {
        return start;
    }

    public String[] getTail() {
        return tail;
    }

    public String getWord() {
        return word;
    }

    /**
     * 计算子表达式的匹配结果
     * @param partExpression 表达式的子串
     * @return
     */
    public Optional<KideMatcheResult> match(String partExpression){
        // 是否满足开始和结束的界限
        boolean isStart = partExpression.startsWith(getStart());
        boolean isTail = false;
        String tailSymbol = null;
        KideMatcheResult kmr = null;
        for(String tmp:getTail()){
            if (null != tmp && partExpression.endsWith(tmp)) {
                isTail = true;
                tailSymbol = tmp;
                break;
            }
        }
        if(isStart && isTail){
            String[] search = Stream.of(new String[]{getStart()}, getTail()).flatMap(Stream::of).toArray(String[]::new);
            String[] replace = new String[search.length];
            Arrays.fill(replace, "");
            String tmpResult = StringUtils.replaceEach(partExpression, search, replace);
            // return Triple.of(getWord(), tmpResult, new String[]{getStart(), tailSymbol});
            kmr = this.build(tmpResult, tailSymbol);
        }
        return Optional.ofNullable(kmr);
    }
    private KideMatcheResult build(String matchValue, String matchTail){
        String temp = matchValue.startsWith(getStart())?matchValue.replace(getStart(), ""):matchValue;
        return KideMatcheResult.Builder.newInstance()
                .attr(getWord())
                .val(temp)
                .start(getStart())
                .finish(matchTail)
                .build();
    }
    /**
     * 计算表达式的匹配结果集合
     * @param express 表达式
     * @param allTails 所有的尾分隔符集合
     * @return
     */
    public Collection<KideMatcheResult> match(final String express, final Set<String> allTails){
        // 拼装开始和结束分隔符
        Collection<KideMatcheResult> result = new ArrayList<>();
        for(String tmpTail : this.getTail()) {
            if (null==tmpTail) {
                logger.debug("[K-MAT][1]current tail is NULL, for value: "+tmpTail);
                continue;
            }
            Pair<Integer, Integer> seekIndexResult = seekIndex(getStart(), tmpTail, express);
            if (null == seekIndexResult){
                logger.debug("[K-MAT][1.1] index seek is lost");
                continue;
            }
            int start = seekIndexResult.getLeft().intValue();
            int finish = seekIndexResult.getRight().intValue();
            logger.debug("[K-MAT][2]seek index start: "+start+", finish: "+finish);
            if (finish == -1) {
                logger.debug("[K-MAT][3]tail: "+tmpTail+", start: "+start+", finish: "+finish);
                continue;
            }
            String temp = null;
            try {
                String s = express.substring(start + (getStart().length()), finish);
                logger.debug("[K-MAT][4] startIndex: " + start + ", finishIndex: " + finish + ", result: " + s + ", startSymbol<> " + getStart() + ", tailSymbol<> " + tmpTail + ", expression: " + express);
                temp = this.isLegalResult(s, allTails);
            }catch (Exception e){}
            // String temp = this.isLegalResult(s, allTails);
            if (null!=temp) {
                logger.debug("[K-MAT][5]match result: "+temp);
                result.add(this.build(temp, tmpTail));
            }
        }
        // System.out.println("<-------------[KM]------------->");
        // result.stream().forEach(System.out::println);
        return result;
    }
    /**
     * 匹配的结果是否包含结束符
     * @param matchResultVal 可能匹配的结果
     * @param allTails 所有分隔符集合
     * @return 包含的即为不合法的结果,不合法的返回null
     */
    private String isLegalResult(final String matchResultVal, final Set<String> allTails){
        long count = allTails.stream().filter(ts -> matchResultVal.indexOf(ts) == -1).count();
        return count == allTails.size() ? matchResultVal : null;
    }
    @Override
    public String toString() {
        return "KideMatcher{" +
                "start='" + start + '\'' +
                ", tail=" + Arrays.toString(tail) +
                ", word='" + word + '\'' +
                '}';
    }

    /**
     * 搜索可能的匹配的下标范围.
     * @param startSymbol 开始分隔符
     * @param tailSymbol 结束分隔符
     * @param target 目标表达式描述符
     * @return 若不满足合法的条件(结束下标大于开始)返回null
     */
    private Pair<Integer,Integer> seekIndex(String startSymbol, String tailSymbol, String target){
        logger.debug("[KM-SEEK][0]start symbol: " +startSymbol+", tail symbol: "+ tailSymbol+", target: "+ target);
        List<Integer> sinSet = CommonHelper.getIndex(target, startSymbol);
        // logger.debug("[KM-SEEK][1]start index: " +sinSet.stream().map(String::valueOf).collect(Collectors.joining()));
        logger.debug("[KM-SEEK][1]start index: " +CommonHelper.toString(sinSet, ","));
        List<Integer> finSet = CommonHelper.getIndex(target, tailSymbol);
        // logger.debug("[KM-SEEK][2]tail index: " +finSet.stream().map(String::valueOf).collect(Collectors.joining()));
        logger.debug("[KM-SEEK][2]tail index: " +CommonHelper.toString(finSet, ","));
        if(finSet.isEmpty() || sinSet.isEmpty()){
            logger.debug("[KM-SEEK][3]start indexSet empty: " +sinSet.isEmpty()+", tail indexSet empty: "+finSet.isEmpty());
            return null;
        }
        // sin 和 fin 哪个只有一个
        if (sinSet.size() == 1) {
            Integer refTailIndex = CommonHelper.getReferElement(sinSet.get(0), finSet, false);
            return (null!=refTailIndex) ? Pair.of(sinSet.get(0), refTailIndex) : null;
        }
        if (finSet.size() == 1) {
            Integer refStartIndex = CommonHelper.getReferElement(finSet.get(0), sinSet, true);
            return (null!=refStartIndex) ? Pair.of(refStartIndex, finSet.get(0)) : null;
        }
        // 若两个都是多个
        return Pair.of(sinSet.get(sinSet.size() - 1), finSet.get(finSet.size() - 1));
    }
}
